home *** CD-ROM | disk | FTP | other *** search
- /* FindCity by Bob Boonstra */
-
- #define kMax 5
- #define kSentinal 0x035A5A5A
- #define low3Bytes 0x00FFFFFF
-
- typedef struct distRec {
- short theDist;
- unsigned short theIndx;
- } distRec;
-
- Boolean FindCity(cityNames, cityToFindNamePtr, closestMatches)
- Str255 cityNames[];
- Str255 *cityToFindNamePtr;
- unsigned short closestMatches[];
- {
- distRec theRec[kMax];
- unsigned char *curCityP, *city2Find;
- unsigned short curIndx;
- register short maxDist;
-
- city2Find = *cityToFindNamePtr;
- curCityP = cityNames[0];
- /*
- * Scan for an exact match.
- */
- {
- register long toFind3;
-
- curIndx = 0;
- toFind3 = *(long *)city2Find & low3Bytes;
- do {
- if ( *(long *)curCityP == *(long *)city2Find ) {
- /*
- * If first 4 characters match, look at the
- * rest in chunks of 4 characters.
- */
- register short charsLeft;
- register unsigned char *s1 = curCityP+4;
- register unsigned char *s2 = city2Find+4;
-
- if ( (charsLeft = *curCityP-7) >= 0 ) {
- do {
- if ( *(long *)s1 != *(long *)s2 )
- goto nextOne;
- s1 += 4; s2 += 4;
- } while ( (charsLeft-=4) >= 0 );
- }
- /*
- * If all chunks of 4 characters match, look at the
- * rest individually.
- */
- if (charsLeft+=4) {
- do {
- if (*s1++ != *s2++)
- goto nextOne;
- } while (--charsLeft);
- }
- /*
- * Exact match found. Return index of match.
- */
- closestMatches[0] = curIndx;
- return(1);
- /*
- * Process the next city. Exit if it is greater in
- * alphabetic order (based on 1st 3 characters,
- * w/o length byte).
- * Sentinal will force exit if necessary.
- */
- nextOne: ;
- }
-
- ++curIndx;
- curCityP+=sizeof(Str255);
-
- } while ( (*(long *)curCityP & low3Bytes) <= toFind3 );
- }
- /*
- * Initialize distance structure for 5 closest matches.
- */
- noMatch:
- {
- register distRec *p = &theRec[0];
-
- (++p)->theDist = (++p)->theDist = (++p)->theDist =
- (++p)->theDist = (p)->theDist = maxDist = 255;
- }
- /*
- * Loop thru cityNames to find closest matches.
- */
- curCityP=cityNames[0];
- curIndx=0;
- do {
- register short curDist;
- /*
- * Calculate dist between cityToFind and cityName[curIndx].
- */
- {
- register unsigned char *s1,*s2;
- register short lng;
-
- /* initialize dist to length difference */
- s2 = city2Find;
- lng = *s2++;
- if ((curDist = *(s1=curCityP) - lng) < 0) {
- curDist = -curDist;
- lng = *s1;
- }
- /*
- * Move to next city if distance exceeds the distance
- * of 5 other cities.
- * Increment dist for each nonMatching char.
- * Unroll for a little extra speed.
- */
- ++s1;
- do {
- if (*s1++ != *s2++)
- if (++curDist >= maxDist) goto nextCity;
- if (!(--lng)) break;
- if (*s1++ != *s2++)
- if (++curDist >= maxDist) goto nextCity;
- if (!(--lng)) break;
- if (*s1++ != *s2++)
- if (++curDist >= maxDist) goto nextCity;
- if (!(--lng)) break;
- if (*s1++ != *s2++)
- if (++curDist >= maxDist) goto nextCity;
- } while (--lng);
- }
- /*
- * This city is closer than at least one of the five
- * currently closest cities. Store the distance and
- * the index in the proper place.
- * distRec[0].theIndx is the closest match, and
- * distRec[0].theDist is the associated distance
- */
- {
- register distRec *q=theRec+kMax-1;
-
- maxDist=curDist;
- if (curDist >= (q-1)->theDist) goto storeIt;
- *q = *(q-1);
- maxDist = q->theDist; --q; /* [3]-->[4] */
- if (curDist >= (q-1)->theDist) goto storeIt;
- *q = *(q-1); --q; /* [2]-->[3] */
- if (curDist >= (q-1)->theDist) goto storeIt;
- *q = *(q-1); --q; /* [1]-->[2] */
- if (curDist >= (q-1)->theDist) goto storeIt;
- *q = *(q-1); --q; /* [0]-->[1] */
- storeIt:
- q->theDist = curDist;
- q->theIndx = curIndx;
- }
- /*
- * Process next city.
- */
- nextCity:
- curCityP+=sizeof(Str255);
- ++curIndx;
- /*
- * Exit when sentinal is found.
- */
- } while (*(long *)curCityP != kSentinal);
-
- /*
- * Return indices of 5 closest cities.
- */
- {
- register unsigned short *p = closestMatches;
- register unsigned short *q = &theRec[0].theIndx;
-
- *p++ = *q; q+=2;
- *p++ = *q; q+=2;
- *p++ = *q; q+=2;
- *p++ = *q; q+=2;
- *p = *q;
- }
- return(0);
- }
-